#ifndef __PIDAUTOTUNER_ZN_H
#define __PIDAUTOTUNER_ZN_H
#include <stdbool.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#include <stdint.h>
typedef enum
{
  ZNModeBasicPID,
  ZNModeLessOvershoot,
  ZNModeNoOvershoot
} ZNMode;
typedef struct pid_autotune_zn
{
  float targetInputValue;
  float loopInterval;
  float minOutput;
  float maxOutput;
  ZNMode znMode;
  uint32_t cycles;
  // See startTuningLoop()
  uint32_t i;
  bool output;
  float outputValue;
  long microseconds;
  long t1;
  long t2;
  long tHigh;
  long tLow;
  float max, min;
  float pAverage;
  float iAverage;
  float dAverage;

  float kp;
  float ki;
  float kd;

} pid_autotune_zn_t;

pid_autotune_zn_t *pid_autotune_zn_create();

void pid_autotune_zn_free(pid_autotune_zn_t *handle);

// Configure parameters for PID tuning
// See README for more details - https://github.com/jackw01/arduino-pid-autotuner/blob/master/README.md
// targetInputValue: the target value to tune to
// loopInterval: PID loop interval in microseconds - must match whatever the PID loop being tuned runs at
// outputRange: min and max values of the output that can be used to control the system (0, 255 for analogWrite)
// znMode: Ziegler-Nichols tuning mode (znModeBasicPID, znModeLessOvershoot, znModeNoOvershoot)
// tuningCycles: number of cycles that the tuning runs for (optional, default is 10)
void pat_zn_set_target_input_value(pid_autotune_zn_t *handle, float target);

void pat_zn_set_loop_interval(pid_autotune_zn_t *handle, long interval);

void pat_zn_set_output_range(pid_autotune_zn_t *handle, float min, float max);

void pat_zn_set_ZNMode(pid_autotune_zn_t *handle, ZNMode zn);

void pat_zn_set_tuning_cycles(pid_autotune_zn_t *handle, int tuneCycles);

// Must be called immediately before the tuning loop starts
void pat_zn_start_tuning_loop(pid_autotune_zn_t *handle, unsigned long us);

// Automatically tune PID
// This function must be run in a loop at the same speed as the PID loop being tuned
// See README for more details - https://github.com/jackw01/arduino-pid-autotuner/blob/master/README.md
float pat_zn_tune_PID(pid_autotune_zn_t *handle, float input, unsigned long us);

// Get results of most recent tuning
float pat_zn_get_kp(pid_autotune_zn_t *handle);

float pat_zn_get_ki(pid_autotune_zn_t *handle);

float pat_zn_get_kd(pid_autotune_zn_t *handle);

bool pat_zn_is_finished(pid_autotune_zn_t *handle); // Is the tuning finished?

int pat_zn_get_cycle(pid_autotune_zn_t *handle); // return tuning cycle

#endif